enum RequestMethod {
    GET = 'GET',
    POST = 'POST',
    PUT = 'PUT',
    DELETE = 'DELETE',
    CONNECT = 'CONNECT',
    HEAD = 'HEAD',
    OPTIONS = 'OPTIONS',
    TRACE = 'TRACE'
}
type ToastIcon = 'success' | 'loading' | 'error' | 'none' | 'fail' | 'exception';

enum LocationType {
    Gcj02 = 'gcj02',
    Wgs84 = 'wgs84'
}

export default class Init {
    url: string;
    imgUrl: string;
    routing: string[];
    constructor({ url, intercept = false, routing = [] }: { url: string; intercept: boolean; routing: string[] }) {
        this.url = `${url}/api/`;
        this.imgUrl = `${url}/static/image/`
        this.routing = routing;
        if (intercept) this.interception()
    }
    /**
     * interception 路由拦截
     * 在需要登录的页面进行判断拦截
     * 注意这里不拦截 switchTab跳转模式需要自行处理
     */
    interception() {
        let _this = this;
        const routingMethods = ['navigateTo', 'redirectTo', 'reLaunch'];
        const routerList = ['pages/index/index']; // 页面白名单
        routingMethods.forEach((method) => {
            uni.addInterceptor(method, {
                invoke(args) {
                    if (!_this.routing.includes(args.url.split('?')[0]) && !uni.getStorageSync('token')) {
                        _this.loginModel()
                        return false
                    }
                }
            })
        })
        // 拦截网络请求
        uni.addInterceptor('request', {
            success: (res) => {
                if (res.data.status == 410000 || res.data.status == 410001 || res.data.status == 410002) {
                    uni.removeStorageSync('token') //移除token
                    let routes = getCurrentPages(); //获取页面路由栈
                    // 判断当前的页面路由是否在在路由白名单 如果不在白名单 &&  不存在token 那么触发登录
                    // #ifdef MP-TOUTIAO
                    if (!_this.routing.includes(routes[routes.length - 1].route) && !uni.getStorageSync('token')) {
                        _this.loginModel()
                        return false
                    }
                    // #endif
                    // != 'pages/index/index'
                    // #ifndef MP-TOUTIAO
                    if (!_this.routing.includes(routes[routes.length - 1].route) && !uni.getStorageSync('token')
                        && !routerList.includes(routes[routes.length - 1].route)) {
                        _this.loginModel()
                        return false
                    }
                    // #endif
                }
            }
        })
    }
    /**
     * 登录模块
     * 登录全部统一进入login页面
     * 如果是H5公众号login也是必须要新建 通过lonig作为中转登录
     */
    loginModel() {
        uni.reLaunch({
            url: '/pages/accout/login'
        })
    }
    /**
     * request 发起网络请求
     * @property {string} url 网络请求地址
     * @property {object} data 请求参数
     * @property {object} header 请求头
     * @property {string} method 请求方式
     */
    async request({ url, data = {}, header = {}, method = RequestMethod.GET }: { url: string; data?: object; header?: object; method: RequestMethod }): Promise<any> {
        let env = 'app'
        // #ifdef APP
        const Formtype = 'app'
        // #endif
        // #ifdef MP-WEIXIN
        const Formtype = 'routine'
        env = wx.getAccountInfoSync().miniProgram.envVersion
        // develop开发版、trial体验版、release正式版
        // #endif
        // #ifdef MP-TOUTIAO
        const Formtype = 'douyin'
        env = tt.getEnvInfoSync().microapp.envType
        // production线上版  development测试版  preview预览版
        // #endif
        // #ifdef H5
        const Formtype = 'wechat'
        // #endif



        try {
            const result = await uni.request({
                url,
                data,
                header: Object.keys(header).length ? header : {
                    "Authori-zation": `Bearer ${uni.getStorageSync('token')}`,
                    "Form-type": Formtype,
                    // #ifndef H5
                    env: env
                    // #endif

                },
                method
            });
            // 一般是在网络请求出错才会触发，比如超时，断网
            if (result.statusCode !== 200) {
                this.hideloading()
                this.model({
                    title: '温馨提示',
                    content: `网络请求失败，状态码${result.statusCode}`,
                    showCancel: false,
                    confirmText: '我知道了'
                })
                return
            }
            if (result.data.status !== 200) return this.toast(result.data.msg)
            return result.data;
        } catch (error) {
            throw error;
        }
    }
    /**
     * get 发起一个get的网络请求
     * @property {string} url 接口地址
     * @property {object} data 请求参数(可选)
     * @property {object} header 请求头(可选)
     */
    async get({ url, data, header }: { url: string; data?: object; header?: object }): Promise<any> {
        const result = await this.request({
            url: `${this.url}${url}`,
            data: data,
            header: header,
            method: RequestMethod.GET
        });
        return result;
    }
    /**
     * post 发起一个post的网络请求
     * @property {string} url 接口地址
     * @property {object} data 请求参数(可选)
     * @property {object} header 请求头(可选)
     */
    async post({ url, data, header }: { url: string; data?: object; header?: object }): Promise<any> {
        const result = await this.request({
            url: `${this.url}${url}`,
            data: data,
            header: header,
            method: RequestMethod.POST
        });
        return result;
    }
    /**
     * put 发起一个put的网络请求
     * @property {string} url 接口地址
     * @property {object} data 请求参数(可选)
     * @property {object} header 请求头(可选)
     */
    async put({ url, data, header }: { url: string; data?: object; header?: object }): Promise<any> {
        const result = await this.request({
            url: `${this.url}${url}`,
            data: data,
            header: header,
            method: RequestMethod.PUT
        });
        return result;
    }
    /**
     * toast 简短提示弹窗
     * @property {string} title 提示内容
     * @property {string} icon 提示的图标 默认none
     */
    toast(title: string, icon: ToastIcon = 'none'): void {
        uni.showToast({
            title: title,
            icon,
            duration: 1500
        });
    }
    /**
     * loading 加载等待框
     * @property {string} title 提示内容
     * @property {boolean} mask 是否阻止穿透 默认false
     */
    loading(title: string, mask: boolean = false): void {
        uni.showLoading({
            title,
            mask
        });
    }
    /**
     * hideloading 隐藏加载等待框
     */
    hideloading(): void {
        uni.hideLoading();
    }
    /**
     * model 确认对话框
     * @property {string} title 对话框标题
     * @property {string} content 对话框显示内容
     * @property {boolean} showCancel 是否显示取消按钮默认true
     * @property {string} confirmText 确认按钮的文字默认'确定'
     * @property {string} cancelText 取消按钮的文字默认'取消'
     */
    async model({
        title,
        content,
        showCancel = true,
        confirmText = '确定',
        cancelText = '取消'
    }: {
        title: string;
        content: string;
        showCancel?: boolean;
        confirmText?: string;
        cancelText?: string;
    }): Promise<boolean> {
        return new Promise((resolve, reject) => {
            uni.showModal({
                title,
                content,
                showCancel,
                confirmText,
                cancelText,
                success: ({ confirm }) => {
                    resolve(confirm);
                },
                fail: (err) => {
                    reject(err);
                }
            });
        });
    }
    /**
     * getlocation 获取当前位置经纬度
     * @property {boolean} altitude 传入 true 会返回高度信息，由于获取高度需要较高精确度，会减慢接口返回速度
     * @property {boolean} geocode 默认false，是否解析地址信息
     */

    getlocation({ altitude = false, geocode = false, type = LocationType.Gcj02 }: { altitude?: boolean; geocode?: boolean; type: LocationType }): Promise<any> {
        return new Promise((resolve, reject) => {
            uni.getLocation({
                altitude,
                type,
                geocode,
                success: ({ latitude, longitude }) => {
                    resolve({ latitude, longitude });
                },
                fail: (err) => {
                    reject(err);
                }
            });
        });
    }

    /**
     * setlist 用作于数据加载更多或者赋值
     * @property { Boolean } isMore 是否属于加载更多
     * @property { Array } listData 用于存储列表数据
     * @property { Number } total 接口数据的总条数
     * @property { Arr+ay } listRow 接口数据条数
     * @property { String } more 加载状态 默认 noMore
     */
    setlist({
        isMore = false,
        listData = {},
        total = 0,
        listRow = [],
        more = {},
        pageNum = {}
    }: {
        isMore: boolean;
        listData: object;
        total: number;
        listRow: object[];
        more: object;
        pageNum: object
    }): void {
        if (isMore) {
            if (listRow.length === 0) {
                more.value = 'noMore';
                pageNum.value--
                return;
            }
            listData.value.push(...listRow);
            more.value = 'more';
            if (listData.value.length === total) {
                more.value = 'noMore';
            }
            return;
        }
        listData.value = listRow;
        more.value = 'more';
        if (listData.value.length === total) {
            more.value = 'noMore';
        }
    }
    /**
     * password 密码强度校验 必须包含数字和字母 密码不能低于6位数&&不能大于20位数
     * @param {String} password 需要校验的密码字符串
     */
    password(password: string): boolean {
        const length = password.length;
        if (length < 6 || length > 20) {
            this.toast('请输入6-20位密码');
            return false;
        }
        const reg = /[0-9]+[a-zA-Z]+[0-9a-zA-Z]*|[a-zA-Z]+[0-9]+[0-9a-zA-Z]*/;
        if (!reg.test(password)) {
            this.toast('密码必须由数字和字母组合');
            return false;
        }
        return true;
    }
    /**
     * copy复制功能
     * @param {String} str 需要复制的文本内容
     */
    copy(str: string): void {
        // #ifdef H5
        const aux = document.createElement('input');
        aux.setAttribute('value', str);
        document.body.appendChild(aux);
        aux.select();
        document.execCommand('copy');
        document.body.removeChild(aux);
        this.toast('复制成功', 'success');
        // #endif

        // #ifndef H5
        uni.setClipboardData({
            data: str.toString()
        });
        // #endif
    }
    /**
     * statusBar 获取手机信号栏那一块区域的高度 获取失败返回25
     */
    statusBar(): number {
        try {
            return uni.getSystemInfoSync().statusBarHeight;
        } catch (a) {
            return 25;
        }
    }
    /**
     * headHeight 获取原生导航栏高度，用于自定义导航栏 ios  44  android 48
     */
    headHeight(): number {
        let h = 0;
        const platform = uni.getSystemInfoSync().platform;
        if (platform == 'ios') {
            h = 44;
        } else if (platform == 'android') {
            h = 48;
        } else {
            h = 44;
        }
        return h;
    }
    /**
     * system 获取当前设备运行系统 返回  ios 或 android
     */
    system(): string {
        let platform = null;
        if (uni.getSystemInfoSync().platform == 'android') {
            platform = 'android';
        }
        if (uni.getSystemInfoSync().platform == 'ios') {
            platform = 'ios';
        }
        return platform;
    }
    /**
     * applePay 苹果支付
     * @param data { } productid = 苹果充值产品ID , order_id = 充值订单ID
     */
    async applePay({ productid, order_id }: { productid: string, order_id: string }): Promise<any> {
        const iapChannel = await this.getApplePay();
        if (!iapChannel) return this.toast('当前环境不支持apple支付')
        return new Promise((resolve, reject) => {
            iapChannel.requestOrder([productid], () => {
                this.hideloading()
                this.loading('支付中...', true)
                uni.requestPayment({
                    provider: 'appleiap',
                    orderInfo: {
                        productid: productid,
                        username: order_id
                    },
                    success: async (res: any) => {
                        this.hideloading()
                        resolve(res)
                    },
                    fail: () => {
                        this.toast('支付取消')
                        this.hideloading()
                    }
                })
            }, async (err: any) => {
                this.hideloading()
                await this.model({
                    title: '温馨提示',
                    content: err.message
                })
                reject(err)
            })
        })
    }
    /**
     * getApplePay 获取苹果支付通道
     */
    getApplePay(): Promise<any> {
        return new Promise((resolve, reject) => {
            uni.getProvider({
                service: 'payment',
                success: (res) => {
                    const iapChannel = res.providers.find((channel) => { return (channel.id === 'appleiap') })
                    iapChannel ? resolve(iapChannel) : resolve(null)
                },
                fail: (err) => {
                    reject(err)
                }
            });
        })
    }
    /**
     * ailpay支付宝支付
     * @param {String} orderInfo 支付宝支付订单数据
     */
    ailpay(orderInfo: string): Promise<any> {
        return new Promise((resolve, reject) => {
            uni.requestPayment({
                provider: 'alipay',
                orderInfo: orderInfo,
                success: function (res) {
                    resolve(res);
                },
                fail: function (err) {
                    reject(err);
                }
            });
        });
    }
    /**
     * wxpay 发起微信支付 在小程序上面发起小程序微信支付 ，在APP发起微信支付
     * @param {Object} orderInfo 支付参数 注意 App端，微信支付 orderInfo 为 Object 类型
     */
    wxpay(orderInfo: string | object): Promise<any> {
        let self = this;
        return new Promise((resolve, reject) => {
            // #ifdef APP
            uni.requestPayment({
                provider: 'wxpay',
                orderInfo: orderInfo,
                success: (res) => {
                    resolve(res);
                },
                fail: (e) => {
                    this.hideloading()
                    this.toast('支付失败或取消支付');
                    reject(e);
                }
            });
            // #endif
            // #ifdef MP-WEIXIN
            uni.requestPayment({
                ...orderInfo,
                success: function (res) {
                    resolve(res);
                },
                fail: (e) => {
                    this.hideloading()
                    this.toast('支付失败或取消支付');
                    reject(e);
                }
            });
            // #endif

            // #ifdef WEB
            WeixinJSBridge.invoke('getBrandWCPayRequest', orderInfo,
                function (res) {
                    if (res.err_msg == "get_brand_wcpay_request:ok") {
                        // 使用以上方式判断前端返回,微信团队郑重提示：
                        //res.err_msg将在用户支付成功后返回ok，但并不保证它绝对可靠。
                        resolve({});
                    } else {
                        console.log(res);
                        self.hideloading()
                        self.toast("支付失败或取消支付");
                        reject("支付失败或取消支付");
                    }

                });
            // #endif
        });
    }




    /**
     * 小程序登录获取code
     */
    getCode(): any {
        return new Promise((callback) => {
            uni.login({
                provider: 'weixin',
                success: ({ code }) => {
                    callback(code);
                },
                fail: (err) => {
                    console.log(err);
                }
            });
        });
    }
    /**
     * formatTime 时间戳转换年月日  或者年月日转时间戳
     * @property {String} timeValue 需要转换的值
     * @property {Sgring} format 数据类型 时间戳转换年月日必传默认yyyy-mm-dd  支持如下类型 yyyy-mm-dd | yyyy年mm月dd日 | yyyy-mm-dd hh:ii:ss | hh:ii:ss
     */
    formatTime(timeValue: number = 0, format: string = 'yyyy-mm-dd'): any {
        if (typeof timeValue === 'number') {
            const date = new Date(timeValue);
            const yyyy = date.getFullYear();
            const mm = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1;
            const dd = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
            const hh = date.getHours() < 10 ? '0' + date.getHours() : date.getHours();
            const ii = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes();
            const ss = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds();
            const placeholders = { yyyy, mm, dd, hh, ii, ss };
            const regex = new RegExp(Object.keys(placeholders).join('|'), 'g');
            return format.replace(regex, (match) => placeholders[match]);
        } else if (typeof timeValue === 'string') {
            if (/\d{4}-\d{2}-\d{2}/.test(timeValue)) {
                return Date.parse(timeValue);
            } else if (/\d{4}年\d{2}月\d{2}日/.test(timeValue)) {
                const [year, month, day] = timeValue.match(/\d+/g).map(Number);
                return Date.UTC(year, month - 1, day);
            } else if (/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(timeValue)) {
                return Date.parse(timeValue.replace(/-/g, '/'));
            } else {
                throw new Error('Invalid date format');
            }
        } else {
            throw new Error('Invalid time value');
        }
    }
    /**
     * 页面跳转通用方法
     * @property {String} url 需要跳转的链接
     * @property {String} type=[open|close|allclose|tab|h5] 跳转的类型
     */
    openWindow(url: string, type: string = 'open'): void {
        switch (type) {
            case 'open':
                uni.navigateTo({
                    url
                });
                break;
            case 'close':
                uni.redirectTo({
                    url
                });
                break;
            case 'allclose':
                uni.reLaunch({
                    url
                });
                break;
            case 'tab':
                uni.switchTab({
                    url
                });
                break;
            case 'h5':
                window.location.href = url;
                break;
            default:
                this.toast('请传递正确的跳转类型', 'none');
                break;
        }
    }
    /**
     * 富文本处理
     * @property {String} c 需要处理的富文本内容
     */
    richtext(c: string): string {
        try {
            c = c.replace(/<p/gi, '<p style="min-height: 22px;"');
            c = c.replace(/<img/gi, '<img style="display:block;max-width: 100%;"');
            c = c.replace(/<video/gi, '<video style="max-width: 100%;"');
            c = c.replace(/<br[^>]*\/>/gi, '');
            c = c.replace(/<td[^<>]*>/gi, '<td style="padding:0px;height:auto;word-break:break-all;">');
            c = c.replace(/<td[^<>]*>\s*?<p>/gi, '<td>');
            c = c.replace(/<th[^<>]*>\s*?<p>/gi, '<th style="width:0">');
            c = c.replace(
                /<table[^>]*>/gi,
                '<table cellpadding="0" cellspacing="0" max-width="100%" border="1" style="font-size:12px;max-width:100%; text-align:left;text-indent: 0em;line-height:12px;"'
            );
            return c;
        } catch (a) {
            return c;
        }
    }
    /**
     * validateInput 校验手机号 身份证号  邮箱 校验失败返回false  type类型不存在则直接返回true
     * @property { string|number } value 需要校验的值
     * @property { string } type=[phone|idcard|email] 校验类型
     *
     */
    validateInput(value: string | number, type: string): boolean {
        let regex, errorMessage;

        switch (type) {
            case 'phone':
                regex = /^1\d{10}$/;
                errorMessage = '请输入正确的手机号码';
                break;
            case 'idcard':
                regex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
                errorMessage = '请输入正确的身份证号码';
                break;
            case 'email':
                regex = /^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/;
                errorMessage = '请输入正确的电子邮件地址';
                break;
            default:
                return true;
        }

        if (regex.test(value)) {
            return true;
        } else {
            uni.showToast({ title: errorMessage, icon: 'none' });
            return false;
        }
    }
    /**
     * updatefile 文件上传
     * @param {Object} e
     */
    updatefile(e: any) {
        return new Promise((resolve, reject) => {
            const uploadTask = uni.uploadFile({
                url: `${this.url}${e.url}`,
                filePath: e.filePath,
                name: e.name,
                fileType: e.fileType ? e.fileType : 'image',
                header: {
                    "Authori-zation": `Bearer ${uni.getStorageSync('token')}`
                },
                formData: {
                    ...e.formData
                },
                success: (res) => {
                    if (res.statusCode == 200) {
                        resolve(JSON.parse(res.data))
                    } else {
                        reject(res)
                        this.model({
                            title: '上传失败',
                            content: JSON.stringify(res.statusCode)
                        })
                    }
                },
                fail: (err) => {
                    reject(err)
                    this.model({
                        title: '上传失败fail',
                        content: JSON.stringify(err)
                    })
                }
            })
            uploadTask.onProgressUpdate((res) => {
                const progress = ((res.totalBytesSent / res.totalBytesExpectedToSend) * 100)
                    .toFixed(0) + '%';
                e.success(res, progress)
            });
        })
    }
    /**
     * dictType 获取数据字典
     * @property { string } types 字典名称
     * @property { string } status 状态码
     */
    dictType(types: string, status: string | number) {
        const dictlist = uni.getStorageSync('dict') || [];
        if (dictlist.length === 0) return '';
        const { dictLabel } = dictlist.filter((val) => val.dictType == types).find((val) => val.dictValue == status) || {};
        if (!dictLabel) return ''
        return dictLabel
    }
    /**
     * formatTimestamp 时间戳转换
     */
    formatTimestamp(timestamp: string | number) {
        const date = new Date(timestamp);
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are zero-based
        const day = String(date.getDate()).padStart(2, '0');
        const hours = String(date.getHours()).padStart(2, '0');
        const minutes = String(date.getMinutes()).padStart(2, '0');
        const seconds = String(date.getSeconds()).padStart(2, '0');
        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    }
    /**
     * getServerNo 检查版本更新
     */
    getServerNo(version, isPrompt = false, callback) {
        const httpData = {
            version_number: version.versionName
        };
        if (this.system() == 'android') {
            httpData.version_type = 2;
        } else {
            httpData.version_type = 1;
        }
        this.get({
            url: 'appUpgrade',
            data: httpData
        }).then(res => {
            if (res.data && res.data.downloadUrl) {
                if (res.data.updateType) {
                    callback && callback(res.data);
                }
            } else if (isPrompt) {
                console.log('暂无新版本');
            }
        })
    }
}
